package com.nervenets.general.web.params;

import com.nervenets.general.Global;
import com.nervenets.general.aspect.validate.Unique;
import com.nervenets.general.exception.LogicException;
import com.nervenets.general.hibernate.TreeDomainObject;
import com.nervenets.general.service.TreeService;
import io.swagger.annotations.ApiModelProperty;
import lombok.*;
import lombok.experimental.SuperBuilder;
import org.springframework.beans.BeanUtils;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.validation.constraints.NotBlank;
import javax.validation.constraints.PositiveOrZero;
import javax.validation.constraints.Size;
import java.lang.reflect.ParameterizedType;
import java.util.List;
import java.util.stream.Collectors;

/**
 * 2020/6/30 11:46 created by Joe
 **/
@EqualsAndHashCode(callSuper = true)
@Setter
@Getter
@AllArgsConstructor
@NoArgsConstructor
@SuperBuilder
public abstract class TreeFormParams<T extends TreeDomainObject<T>, Service extends TreeService<T>> extends FormParams<T, Service> {
    @ApiModelProperty(value = "名称", required = true)
    @NotBlank
    @Size(max = 191)
    private String name;
    @ApiModelProperty(value = "父级")
    private long parentId;
    @ApiModelProperty("排序")
    @PositiveOrZero
    private int queue;
    @ApiModelProperty("是否启用")
    private boolean enable = true;
    @ApiModelProperty(value = "子级（当在树中间插入节点时用）")
    @Unique
    private List<Long> childrenIds;

    @SneakyThrows
    @Override
    public T validateAndBuild(Service service, HttpServletRequest request, HttpServletResponse response) {
        Class<T> entityClass = (Class<T>) ((ParameterizedType) getClass().getGenericSuperclass()).getActualTypeArguments()[0];
        T t = entityClass.newInstance();
        if (getFormId() > 0) {
            t = service.findOne(getFormId(), "您要编辑的数据不存在，请刷新后再试。");
        }
        if (parentId > 0) {
            service.findOne(parentId, "您选择的父级不存在");

            if (!t.isNew()) {
                List<Long> childrenIds = service.findAllChildrenByParentId(t.getId()).stream().map(TreeDomainObject::getId).collect(Collectors.toList());
                childrenIds.add(t.getId());
                if (childrenIds.contains(parentId)) throw new LogicException("不能将父级设置为当前节点或其子结点，否则将造成无限死循环。");
            }
        }

        BeanUtils.copyProperties(this, t, Global.defaultIgnoreProperties(nullProperties()));

        if (null != childrenIds && !childrenIds.isEmpty()) {
            t.setChildren(service.findAllByIds(childrenIds));
        }

        return t;
    }
}
